/**************************************************************************************
*
*	Copyright (C) 2009 Brent Andrew Chua - See LICENSE.txt for more info.
*		
*	Filename	-	WinApp.h
*
*	Description -	Encapsulates windows code stuff.
*
*	Comments	-	If you don't understand some part of the code, use MSDN!!!
*						Move the cursor to the function/type then hit F1 in VS.
*
*	Modification History:
*			Name			   Date					Description
*			CodeSushi	-	11/16/2009	-	Creation of this file
**************************************************************************************/

#ifndef _PSX_WINAPP_H_
#define _PSX_WINAPP_H_

#include <windows.h>
#include "CSGD_DirectSound.h"
#include "CSGD_WaveManager.h"

#include "../../Pulse Lib/Include/Pulse.h"
#include "BackBuffer.h"
#include "SoundSystem.h"

class WinApp;

// Other systems can simply use this global pointer to access some necessary information.
extern WinApp *gpWinApp; 

using namespace Pulse;

class WinApp
{
public:

	WinApp( const HINSTANCE hInst, const CHAR *pStr, const INT posX, const INT posY, const INT width, const INT height );
	virtual ~WinApp( void ) { }

	Pulse::BOOL InitializeWindow( Pulse::BOOL showWindow = TRUE, INT shwCmd = 1 );

	// Windows app methods
	void ShowWindow( INT shwCmd = 1  );
	Pulse::BOOL SetWindowPos( INT newX, INT newY );
	Pulse::BOOL SetWindowSize( INT width, INT height );
	Pulse::BOOL ResizeWindow( INT newX, INT newY, INT width, INT height );
	Pulse::BOOL CenterWindow( void );
	Pulse::BOOL ToggleFullScreen( void );
	Pulse::BOOL IsFullScreen( void );
	void ShowCursor( Pulse::BOOL bShow = TRUE );
	void HideCursor( void );
	Pulse::BOOL IsKeyDown( INT vKey );
	Pulse::BOOL IsBufferedKeyDown( INT vKey );
	Pulse::BOOL IsBufferedDoubleKeyDown( INT vKey1, INT vKey2 );

	INT GetAppCursorPos( POINT &point );
	INT GetCursorPos( POINT &point );
	HINSTANCE GetHInstance( void ) const;

	// TODO: Provide some text, and GDI,GDI+ functionality
	// --

	FLOAT GetElapsedTime( void );
	FLOAT GetTotalTime( void );

	INT Run( void );

	// Debug method. Measure performance in Frames Per Second.
	void ShowFPS( Pulse::BOOL showFPS );
	
protected:

	/* Functions that would probably never be redefined but just in case... */

	Pulse::BOOL SetDisplayMode( const INT width, const INT height, const INT bitsPerPix, const DWORD refreshRate );

	// These functions shouldn't prolly be virtuals....
	virtual Pulse::BOOL _RegisterWindowClass( void );
	virtual Pulse::BOOL _CreateWindow( void );
	virtual Pulse::BOOL _OnDeviceReset( void );
	virtual Pulse::BOOL _OnUpdate( void );
	virtual Pulse::BOOL _OnShutDown( void );

	// Event messages function handlers
	virtual LRESULT OnWMCreateWindow( void );
	virtual LRESULT OnWMDestroyWindow( void );
	virtual LRESULT OnWMMove( void );
	virtual LRESULT OnWMPaint( void );
	virtual LRESULT OnWMGainFocus( void );
	virtual LRESULT OnWMLoseFocus( void );
	virtual LRESULT OnWMQuit( void );

protected:

	/* Common methods the derived app class needs to redefine. */

	virtual Pulse::BOOL OnStart( void )			{ return TRUE;  }	// Called just before the app enters in the main loop.
	virtual Pulse::BOOL OnUpdate( FLOAT dt )	{ return FALSE; }	// dt : Elapsed time or delta time from the last frame to current frame.
	virtual Pulse::BOOL OnRender( void )		{ return TRUE;  }	// Called every frame for rendering objects
	virtual Pulse::BOOL OnExit( void )			{ return TRUE;  }	// Called just before the application quits.
	virtual Pulse::BOOL OnDeviceReset( void )	{ return TRUE;  }	// This is called when _OnDeviceReset is triggered.

protected:

	static LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
	// Store WndProc param vars here for easier access of On...function events.
	UINT		msg;
	WPARAM		wParam;
	LPARAM		lParam;

	HINSTANCE	m_hInstance;		// Instance of this app.
	HWND		m_hWnd;				// Handle to this window app
	MSG			m_msg;				// Current message. Place it here to avoid creating everytime.
	
	// Application Info
	String		m_appName;			// Name of the application
	WNDCLASSEX	m_wndClass;			// Window class definition
	INT			m_appPosX, m_appPosY;		// Application position
	INT			m_appWidth, m_appHeight;	// Application size

	// Application run-time Info
	Pulse::BOOL m_fullScreen;		// Boolean to let us know whether we're in fullscreen mode or not.
	FLOAT		m_dt;				// Delta-time. Difference between the last and current frame.
	FLOAT		m_totalTime;		// Total elapsed time that has passed since the app started running.
	BackBuffer	*m_pBackBuffer;		// We will be rendering all our objects here before we present to the front buffer.
	HDC			m_spriteDC;			// This device context will be used for rendering our sprites/bitmaps objects.

	// We're using Direct Sound for handling our sound stuff...
	class CSGD_DirectSound	*m_pDS;
	class CSGD_WaveManager	*m_pWaveMan;

	// Our new sound system now uses FMOD. CSGD_Wavemanager and CSGD_DirectSound is now deprecated.
	SoundSystem *m_pSoundSystem;

private:

	void HandleFPS( void );
	void UpdateVKeyMap( void );

	UCHAR		m_VKMap[256];		// This is used for buffered key. See IsBufferedKeyDown()...
	UCHAR		m_VKMapGhost[256];	// This is needed for VKMap to solve the issue of calling the same VK more than once per frame.
	Pulse::BOOL	m_showFPS;			// Bolean for seting FPS debug performance info
	Pulse::BOOL m_paused;			// If the window is active don't run the program.
};

// This is the same as IsKeyDown
#define KEYDOWN(vkcode) (GetAsyncKeyState(vkcode)&0x8000 ? true : false)

PSX_INLINE Pulse::BOOL WinApp::IsKeyDown( INT vKey )
{
	PSX_Assert( vKey >= 0 && vKey <= 256, "vKey out of bound." );
	return GetAsyncKeyState( vKey ) &0x8000 ? TRUE : FALSE;
}

PSX_INLINE HINSTANCE WinApp::GetHInstance( void ) const
{
	return m_hInstance;
}

PSX_INLINE FLOAT WinApp::GetElapsedTime( void )
{
	return m_dt;
}

PSX_INLINE FLOAT WinApp::GetTotalTime( void )
{
	return m_totalTime;
}

PSX_INLINE Pulse::BOOL WinApp::IsBufferedDoubleKeyDown( int vKey1, int vKey2 )
{
	if ( (IsKeyDown( vKey1 ) && IsBufferedKeyDown( vKey2 )) ||
		(IsKeyDown( vKey2 ) && IsBufferedKeyDown( vKey1 )) )
		return TRUE;

	return FALSE;
}

PSX_INLINE void WinApp::ShowFPS( Pulse::BOOL showFPS )
{
	m_showFPS = showFPS;
}
bool RectRectCollisionCheck( RECT &r1, RECT &r2 );
#endif /* _PSX_WINAPP_H_ */